#ifdef _WIN32
#include "stdafx.h"
#endif
///////////////// C M D
void game_machine :: cast_cmd   (short emit, short abil, short target)
{
    LOGMSG("[cmd] "+ inspect_cast(emit, abil, target));

	if(Abilities[abil].on_cooldown) // cooldown check
    { error_message(is_on_cooldown); return; }

    if(Characters[emit].mana < Abilities[abil].cost)
    { error_message(out_of_mana); return; }

    if(Abilities[abil].range == 0) // self emit, no range check or missile emit
    { cast_start(emit, abil, target); return; }

    float range_sqrd = float(Abilities[abil].range); // will be used in both target and aoe
    range_sqrd *= range_sqrd;

    //if(Abilities[abil].mask & MISSILE) // requires target ?
    //   if(sqrd_dist(CharPositions[emit], CharPositions[target]) > range_sqrd)
    //    { error_message(too_far_away1); return; }
    //else // doesn't require target, check for clicked position range
    //    if(sqrd_dist(CharPositions[emit], click_position) > range_sqrd)
    //    { error_message(too_far_away2); return; }
    /* lacks obstacle check, will require raycast etc */
    cast_start(emit, abil, target);
}

///////////////// S T A R T
void game_machine :: cast_start  (short emit, short abil, short target)
{
    LOGMSG("[start] "+ inspect_cast(emit, abil, target));
    
    if(Abilities[abil].cooltime > 0.0f) // charging spell
    {
        size_t pos;
        Timers.add(pos);
        Abilities[abil].on_cooldown = true;
        
        Timers[pos].abil = abil;
        Timers[pos].emit = emit;
        Timers[pos].target = target;
        
        LOGMSG("Charging timer "+TO_STR(pos));
        Timers[pos].state = casting;
        Timers[pos].delay = Abilities[abil].cooltime;
        
        bar.period = Abilities[abil].cooltime;
        bar.current = 0;
        bar.inverse = 1.0f / Abilities[abil].cooltime;
    }
    else
        cast_launch(emit, abil, target);
}

///////////////// L A U N C H
void game_machine :: cast_launch (short emit, short abil, short target)
{
    // In this function we finalize casting for both charging and cooldown spells
    LOGMSG("[launch] "+ inspect_cast(emit, abil, target));
    
    if(Abilities[abil].cooltime < 0.0f) // cooldown spell
    {
        size_t pos;
        Timers.add(pos);
        Abilities[abil].on_cooldown = true;
        
        Timers[pos].abil = abil;
        Timers[pos].emit = emit;
        Timers[pos].target = target;
        
        LOGMSG("Cooldown timer "+TO_STR(pos));
        Timers[pos].state = cooldown;
        Timers[pos].delay = - Abilities[abil].cooltime;
        
        bar.period = - Abilities[abil].cooltime;
        bar.current = 0;
        bar.inverse = 1.0f / - Abilities[abil].cooltime;
    }
    if(Abilities[abil].velocity == 0) // instant travel
        cast_land(emit, abil, target);
    else
        cast_land(emit, abil, target);
    
    // spawn_timer     // launch missile with missile_mgr or smth.
}

///////////////// L A N D
void game_machine :: cast_land   (short emit, short abil, short target)
{     
    char radius = Abilities[abil].radius;
    LOGMSG("[land] "+ inspect_cast(emit, abil, target));
    if(radius == 0)
    {
        if(Abilities[abil].ticks == 0)
        {
            LOGMSG("direct damage ! "+TO_STR(Abilities[abil].dmg));
            Characters[target].life -= Abilities[abil].dmg;
        }
        else // has dot
        {
            LOGMSG("dot damage !");
            cast_dot(emit, abil, target);
        }
    }
    else
    {
        Vec3 sphere_orig;
        LOGMSG("area damage !");
        if(Abilities[abil].range == 0) // self emit
            sphere_orig = appli->Nodes[emit]->getPosition();
        else if(Abilities[abil].mask & MISSILE) // 
        {}//sphere_orig = projectile;

        // do the sc query
    }

}
///////////////// D O T
void game_machine :: cast_dot    (short emit, short abil, short target)
{

    LOGMSG("[dot] "+ inspect_cast(emit, abil, target));
    size_t pos;
    Timers.add(pos);
    
    Timers[pos].state = dotted;
    Timers[pos].target = target;
    Timers[pos].emit = emit;
    Timers[pos].abil = abil;

    Timers[pos].ticks_left = Abilities[abil].ticks;
}

